// Copyright (C) 1995 Steve Hayman
// Use is governed by the MiscKit license

#import "Controller.h"
#import <misckit/misckit.h>
#import "MiscViews.subproj/MiscIconWell.h"
#import <stdio.h>

@implementation Controller

- appDidInit:sender
{
    char bundleTemplates[MAXPATHLEN+1];
    FILE *p;
    MiscString *cmdline = [[MiscString alloc] init];
    MiscString *aFile = [[MiscString alloc] init];
        
    /*
     * Set up some defaults
     */
    static NXDefaultsVector myDefaults = {
	{"OpenInProjectBuilder", "YES"},
	{NULL}
    };
    
    [NXApp registerDefaults:myDefaults];
    
    templateList = [[MiscStringArray alloc] init];
    [templates setDelegate:templateList];
    templatePathnames = [[MiscStringArray alloc] init];
	    
    [[NXBundle mainBundle] getPath:bundleTemplates
	    forResource:"QuickProjectTemplates" ofType:NULL];
    
    /*
     * Run a simple command to retrieve a list of all the possible
     * project templates.
     * TODO - use a MiscSubprocess here (maybe - might be overkill)
     */
    /*
     * Use ls rather than echo just so we get output files one per line.
     */
    [cmdline catFromFormat:"/bin/ls -d ~/Library/QuickProjectTemplates/* /LocalLibrary/QuickProjectTemplates/* %s/*", bundleTemplates];
    
	
    p = popen([cmdline stringValue], "r");
    
    if ( p ) {
	// read filenames, add to the lists.
	[aFile setStringValue:""];
	while ( [aFile fgets:p keepNewline:NO] != EOF ) {
	    
	    // Keep a list of full pathnames in templatePathnames;
	    // keep a parallel list of filenames in templateList, which
	    // is what's displayed in the browser.
	    [templatePathnames addString:[aFile stringValue]];
	    [templateList addString: 
		[[aFile fileName] stringValueAndFree]];
	    
	    [aFile setStringValue:""];
	}
	[templates loadColumnZero];
	[self showSelectedPath:templates];

	pclose(p);
    } else {
	NXRunAlertPanel([NXApp appName], 
	    "Couldn't make list of project templates", NULL,NULL,NULL);
    }
    
    /*
     * And finally, select the Name text as a convenience.
     */
    [name selectText:self];
    
    /*
     * Register to receive TIFF services.   So you can use Grab to get
     * an icon, which we'll make into an image and paste into the
     * icon well.
     */
    {
	const char *returnTypes[2];
	returnTypes[0] = NXTIFFPboardType;
	returnTypes[1] = NULL;
	[NXApp registerServicesMenuSendTypes:NULL andReturnTypes:returnTypes];
    }
    return self;
}


/*
 * Save the icon, if there is one, to a temporary file and return
 * a MiscString containing its pathname.
 */
 
- saveIconToTempFile
{
    MiscString *filename;
    NXStream *str;
    if ( ! [iconWell image] )
	return nil;
	
    filename = [[MiscString alloc] init];
    [filename catFromFormat:"/tmp/icon%d.tiff", getpid()];
    
    str = NXOpenMemory(NULL, 0L, NX_READWRITE);
    [[iconWell image] writeTIFF:str];
    NXSaveToFile( str, [filename stringValue] );
    NXCloseMemory(str, NX_FREEBUFFER);
    
    return filename;
}
- saveAs:sender
{
    id sp = [SavePanel new];
    MiscString *cmd = [[MiscString alloc] init];
    const char *filename;
    const char *templatePath;
    int pos;
    MiscSubprocess *proc;
    NXBundle *mainBundle = [NXBundle mainBundle];
    id selectionList = [[List alloc] init];
    MiscString *iconFileName;
    
    if ( ! [name stringValue] || (strlen([name stringValue]) == 0) ) {
	NXRunAlertPanel([NXApp appName],
	    "Please supply a name for your project.",
	    NULL,NULL,NULL);
	return nil;
    }
    
    
    if ( [sp runModalForDirectory:NULL file: [name stringValue]] ) {
	filename = [sp filename];
	destinationFile = [MiscString newWithString:filename];
	
	// Save the icon image - if there is one - in a file so that
	// we can pass its pathname to copy_project.
	
	iconFileName = [self saveIconToTempFile];

	// Now copy the chosen project.  Figure out the index of
	// the selected cell, and ask the templateList for the full
	// string value at that position -not just the basename 
	// displayed in the browser	
	pos = [[templates matrixInColumn:0] selectedRow];
	templatePath = [templatePathnames stringAt:pos];
	
	// copy_project  template_dir dest_dir template_name appname
	
	[cmd sprintf:"%s/copy_project %s %s %s %s %s", 
	    [mainBundle directory],
	    templatePath,
	    [sp filename],
	    [templates stringValue],
	    [name stringValue],
	    iconFileName ? [iconFileName stringValue] : ""];

	

	[iconFileName free];
		
	/*
	 * Fire up a MiscSubprocess object to execute the copy command.
	 */

	proc = [[MiscSubprocess alloc]
	    init:[cmd stringValue]
	    withDelegate:self];
    }
    [cmd free];
    [selectionList free];
    return self;

}
/*
 * This is the target of the browser.   The browser shows only the
 * basename of the project template you've chosen; display its full
 * path as well.  (Except we replace the home directory with "~" since it
 * takes up less space on the screen.)
 */

- showSelectedPath:sender
{
    int selection = [[sender matrixInColumn:0] selectedRow];
    id templatePath = [MiscString newWithString: [templatePathnames stringAt:selection]];
    
    [templatePath replaceHomeWithTilde];	// looks nicer. less room too.
    [selectedTemplatePath
	    setStringValue: [templatePath stringValueAndFree]];
    return self;
}


/*
 * Subprocess delegate methods
 */
- subprocess:sender done:(int)status :(MiscSubprocessEndCode)code
{
    MiscString *projectFile;
    [sender terminate:self];
    [sender free];
    
    if ( code == Misc_Exited && status == 0 ) {
	/*
	 * message Workspace here to open the PB.project
	 */
	
	
	
	if ( [NXApp defaultBoolValue:"OpenInProjectBuilder"] ) {
	
	    /*
	    * Figure out the path to the PB.project file
	    */
	    projectFile = [destinationFile copy];
	    [projectFile cat:"/PB.project"];

	    [[[self log:"Opening project file "]
		log:[projectFile stringValue]]
		log:"\n"];

	    [[Application workspace] openFile:[projectFile stringValue]];
	    [projectFile free];
	}
	NXRunAlertPanel([NXApp appName],
	    "Project created succesfully.", "OK", NULL, NULL);
    }
    return self;
}
- subprocess:sender output:(const char *) buffer
{
    [self log:buffer];

    return self;
}
- subprocess:sender stderrOutput:(const char *)buffer
{
    [self log:buffer];
    return self;
}
- subprocess:sender error:(const char *)errorString
{
    [self log:"Error: "];
    [self log:errorString];

    return self;
}

- log:(const char *)str
{
    int len;
    if ( ! processLog ) 
	[NXApp loadNibSection:"SubprocessLog.nib" owner:self];
    len = [processLog textLength];
    [processLog setSel:len:len];
    [processLog replaceSel:str];
    [processLog scrollSelToVisible];
    [[processLog window] makeKeyAndOrderFront:self];
    return self;
}

/*
 * Preferences handling
 */

- showPreferences:sender
{
    if ( ! prefsPanel ) {
	[NXApp loadNibSection:"Preferences.nib" owner:self];
	[openInPBSwitch setState: 
	    [NXApp defaultBoolValue:"OpenInProjectBuilder"]];
    }
	
    [self revert:self];
    [prefsPanel makeKeyAndOrderFront:self];
    return self;
}

- ok:sender
{
    [NXApp setBoolDefault:"OpenInProjectBuilder" to: [openInPBSwitch state]];
    
    return self;
}

- revert:sender
{
    [openInPBSwitch setState: [NXApp defaultBoolValue:"OpenInProjectBuilder"]];
    
    return self;
}


/*
 * A couple of methods that support doing Services -> Grab
 * so we can pick up a tiff and use it as our icon
 */

- validRequestorForSendType:(NXAtom)typeSent
                        andReturnType:(NXAtom)typeReturned
{
    if ( typeSent == NULL && typeReturned == NXTIFFPboardType )
	return self;
    return nil;
}

- readSelectionFromPasteboard:pb
{
    id image = [[NXImage alloc] initFromPasteboard:pb];
    /*
     * what we should do here is save the image to a temp file,
     * and tell the icon well that that's the filename.
     * but this is quicker for now even though not what we want.
     */
    [iconWell setImage: image];
    return self;
}

/*
 * Some more methods that allow pasting a TIFF selection.
 */

- paste:sender
{
    id pb = [Pasteboard new];
    BOOL tiffFound = NO;
    const NXAtom *types;
    NXImage *pasteImage;
    
    types = [pb types];
    /*
     * is there TIFF on the pasteboard?
     */
    if ( types ) {
	while ( *types ) {
	    if ( *types++ == NXTIFFPboardType ) {
		tiffFound = YES;
		break;
	    }
	}
    }

    if ( ! tiffFound )
	return nil;
	
    pasteImage = [[NXImage alloc] initFromPasteboard:pb];
    [iconWell setImage: pasteImage];	// don't free it. iconwell keeps it.
    
    return self;
}

@end
